package flc.ast.utils;

import android.text.TextUtils;
import android.util.Log;

import com.blankj.utilcode.util.GsonUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.stark.irremote.lib.R;
import com.stark.irremote.lib.base.IrComRemoteController;
import com.stark.irremote.lib.base.IrUtil;
import com.stark.irremote.lib.base.bean.AcRemoteStatusInfo;
import com.stark.irremote.lib.base.bean.IrRemote;
import com.stark.irremote.lib.base.db.IrRemoteDbHelper;
import com.stark.irremote.lib.base.key.IrAcKey;
import com.stark.irremote.lib.net.bean.IrRemoteIndex;

import net.irext.decode.sdk.IRDecode;
import net.irext.decode.sdk.bean.ACStatus;
import net.irext.decode.sdk.bean.TemperatureRange;
import net.irext.decode.sdk.utils.Constants;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import androidx.annotation.Keep;
import androidx.annotation.NonNull;

/**
 * Author：daizhongbin on 2022/4/21
 * Email：1027154338@qq.com
 * Desc: 空调遥控控制器
 */
@Keep
public class MyIrAcRemoteController extends IrComRemoteController {

    private static final String TAG = MyIrAcRemoteController.class.getSimpleName();

    //无效温度
    private static final int INVALID_TEMP = 0XFF;

    private ACStatus mAcStatus;
    //保存各模式下的温度的map集合
    private Map<Integer, Integer> mModeTempMap = new HashMap<>();
    //保存各模式下的风速的map集合
    private Map<Integer, Integer> mModeSpeedMap = new HashMap<>();
    //保存各模式下的扫风状态的map集合
    private Map<Integer, Integer> mModeSwingMap = new HashMap<>();
    //当前遥控器所支持的模式列表
    private List<Constants.ACMode> mSupportModes = new ArrayList<>();

    public static MyIrAcRemoteController create(@NonNull IrRemoteIndex remoteIndex) {
        String binFilePath = IrUtil.generateRemoteIdxFilePath(remoteIndex.remoteMap, remoteIndex.id);
        int ret = IRDecode.getInstance().openFile(remoteIndex.categoryId, remoteIndex.subCate, binFilePath);
        MyIrAcRemoteController controller = null;
        if (ret == 0) {
            controller = new MyIrAcRemoteController(IRDecode.getInstance(), remoteIndex);
        } else {
            ToastUtils.showShort(R.string.ir_open_remote_file_failure);
        }
        return controller;
    }

    public static MyIrAcRemoteController create(@NonNull IrRemote irRemote) {
        String binFilePath = IrUtil.generateRemoteIdxFilePath(irRemote.remoteMap, irRemote.remoteIdxId);
        int ret = IRDecode.getInstance().openFile(irRemote.categoryId, irRemote.subCate, binFilePath);
        MyIrAcRemoteController controller = null;
        if (ret == 0) {
            controller = new MyIrAcRemoteController(IRDecode.getInstance(), irRemote);
        } else {
            ToastUtils.showShort(R.string.ir_open_remote_file_failure);
        }
        return controller;
    }

    private MyIrAcRemoteController(@NonNull IRDecode irDecode, @NonNull IrRemoteIndex remoteIndex) {
        super(irDecode, remoteIndex);
        init();
    }

    private MyIrAcRemoteController(@NonNull IRDecode irDecode, @NonNull IrRemote remote) {
        super(irDecode, remote);
        init();
    }

    private void init() {
        initSupportModes();

        if (mRemote != null && !TextUtils.isEmpty(mRemote.statusInfo)) {
            AcRemoteStatusInfo statusInfo = GsonUtils.fromJson(mRemote.statusInfo, AcRemoteStatusInfo.class);
            if (statusInfo != null && statusInfo.acStatus != null) {
                mAcStatus = statusInfo.acStatus;
                mModeTempMap = statusInfo.getModeTempMap();
                mModeSpeedMap = statusInfo.getModeSpeedMap();
                mModeSwingMap = statusInfo.getModeSwingMap();
                return;
            }
        }

        ACStatus status = new ACStatus();
        mAcStatus = status;
        //power
        status.setAcPower(Constants.ACPower.POWER_OFF.getValue());

        //mode
        Constants.ACMode curMode = mSupportModes.get(0);
        status.setAcMode(curMode.getValue());

        //temp
        TemperatureRange tempRange = mIrDecode.getTemperatureRange(curMode.getValue());
        int temp = -1; //-1表示当前模式下不支持温度调节
        if (tempRange.getTempMin() != INVALID_TEMP && tempRange.getTempMax() != INVALID_TEMP) {
            //取一个折中的温度
            temp = tempRange.getTempMin() + (tempRange.getTempMax() - tempRange.getTempMin()) / 2;
        }
        status.setAcTemp(temp);
        mModeTempMap.put(curMode.getValue(), temp);

        //wind speed
        int speed = -1;
        List<Constants.ACWindSpeed> windSpeedList = getSupportedWindSpeeds(curMode.getValue());
        if (windSpeedList.size() > 0) {
            speed = windSpeedList.get(0).getValue();
        }
        status.setAcWindSpeed(speed);
        mModeSpeedMap.put(curMode.getValue(), speed);

        //swing
        int windDir = -1;
        int supportedSwing = mIrDecode.getACSupportedSwing(curMode.getValue());
        if (supportedSwing == 2 || supportedSwing == 3) {
            windDir = Constants.ACSwing.SWING_ON.getValue();
        }
        status.setAcWindDir(windDir);
        mModeSwingMap.put(curMode.getValue(), windDir);
    }

    public ACStatus getAcStatus() {
        return mAcStatus.copy();
    }

    private void initSupportModes() {
        mSupportModes.clear();

        int[] supportedMode = mIrDecode.getACSupportedMode();
        for (int i = 0; i < supportedMode.length; i++) {
            if (supportedMode[i] == 1) {
                mSupportModes.add(Constants.ACMode.getModeByValue(i));
            }
        }
    }

    @Override
    public void handleIrKey(int keyCode) {
        if (!mIrManager.hasIrEmitter()) {
            Log.e(TAG, "handleIrKey: no ir emitter.");
            return;
        }
        IrAcKey key = IrAcKey.getAcKeyByValue(keyCode);
        if (key == null) return;

        switch (key) {
            case POWER:
                handlePowerKey();
                break;
            case MODE:
                handleModeKey();
                break;
            case TEMP_ADD:
                handleTempAddKey();
                break;
            case TEMP_MINUS:
                handleTempMinusKey();
                break;
            case WIND_SPEED:
                handleWindSpeedKey();
                break;
            case SWEEP_WIND:
                handleSweepWindKey();
                break;
            case WIND_DIR:
                break;
        }
    }

    /**
     * 电源按键处理
     */
    private void handlePowerKey() {
        //更新状态
        int curPower = mAcStatus.getAcPower();
        int newPower = Constants.ACPower.POWER_OFF.getValue();
        if (curPower == Constants.ACPower.POWER_OFF.getValue()) {
            newPower = Constants.ACPower.POWER_ON.getValue();
        }
        mAcStatus.setAcPower(newPower);

        //通知状态刷新
        notifyStatusChanged();

        //发送红外码
        int keyCode = IrAcKey.POWER.getValue();
        int[] codes = mIrDecode.decodeBinary(keyCode, mAcStatus, 0);
        mIrManager.transmit(FREQUENCY, codes);
    }

    /**
     * 模式按键处理
     */
    private void handleModeKey() {
        if (isInPowerOff()) {
            ToastUtils.showShort(R.string.ir_not_use_in_power_off);
            return;
        }

        //更新状态
        //mode
        Constants.ACMode curMode = Constants.ACMode.getModeByValue(mAcStatus.getAcMode());
        int index = mSupportModes.indexOf(curMode);
        Constants.ACMode newMode;
        if (index >= mSupportModes.size() - 1) {
            newMode = mSupportModes.get(0);
        } else {
            newMode = mSupportModes.get(index + 1);
        }
        mAcStatus.setAcMode(newMode.getValue());

        //temp
        int temp = -1;
        if (mModeTempMap.containsKey(newMode.getValue())) {
            temp = mModeTempMap.get(newMode.getValue());
        } else {
            TemperatureRange tempRange = mIrDecode.getTemperatureRange(newMode.getValue());
            if (tempRange.getTempMin() != INVALID_TEMP && tempRange.getTempMax() != INVALID_TEMP) {
                //取一个折中的温度
                temp = tempRange.getTempMin() + (tempRange.getTempMax() - tempRange.getTempMin()) / 2;
            }
        }
        mAcStatus.setAcTemp(temp);
        mModeTempMap.put(newMode.getValue(), temp);

        //wind speed
        int speed = -1;
        if (mModeSpeedMap.containsKey(newMode.getValue())) {
            speed = mModeSpeedMap.get(newMode.getValue());
        } else {
            List<Constants.ACWindSpeed> windSpeedList = getSupportedWindSpeeds(newMode.getValue());
            if (windSpeedList.size() > 0) {
                speed = windSpeedList.get(0).getValue();
            }
        }
        mAcStatus.setAcWindSpeed(speed);
        mModeSpeedMap.put(newMode.getValue(), speed);

        //swing
        int windDir = -1;
        if (mModeSwingMap.containsKey(newMode.getValue())) {
            windDir = mModeSwingMap.get(newMode.getValue());
        } else {
            int supportedSwing = mIrDecode.getACSupportedSwing(newMode.getValue());
            if (supportedSwing == 2 || supportedSwing == 3) {
                //要切换到的模式是支持控制扫风的
                windDir = mAcStatus.getAcWindDir();
                if (windDir == -1) {
                    //之前的模式不支持控制扫风，则要改变新模式下的值
                    windDir = Constants.ACSwing.SWING_ON.getValue();
                }
            }
        }
        mAcStatus.setAcWindDir(windDir);
        mModeSwingMap.put(newMode.getValue(), windDir);

        //通知状态刷新
        notifyStatusChanged();

        //发送红外码
        int keyCode = IrAcKey.MODE.getValue();
        int[] codes = mIrDecode.decodeBinary(keyCode, mAcStatus, 0);
        mIrManager.transmit(FREQUENCY, codes);
    }

    /**
     * 温度+按键处理
     */
    private void handleTempAddKey() {
        if (isInPowerOff()) {
            ToastUtils.showShort(R.string.ir_not_use_in_power_off);
            return;
        }

        //判断当前模式是否支持温度控制
        int curTemp = mAcStatus.getAcTemp();
        if (curTemp == -1) {
            ToastUtils.showShort(R.string.ir_not_support_temp_tip);
            return;
        }

        //更新状态
        //temp
        TemperatureRange range = mIrDecode.getTemperatureRange(mAcStatus.getAcMode());
        if (curTemp < range.getTempMax()) {
            curTemp++;
        }
        mAcStatus.setAcTemp(curTemp);
        mModeTempMap.put(mAcStatus.getAcMode(), curTemp);

        //通知状态刷新
        notifyStatusChanged();

        //发送红外码
        int keyCode = IrAcKey.TEMP_ADD.getValue();
        int[] codes = mIrDecode.decodeBinary(keyCode, mAcStatus, 0);
        mIrManager.transmit(FREQUENCY, codes);
    }

    /**
     * 温度-按键处理
     */
    private void handleTempMinusKey() {
        if (isInPowerOff()) {
            ToastUtils.showShort(R.string.ir_not_use_in_power_off);
            return;
        }

        //判断当前模式是否支持温度控制
        int curTemp = mAcStatus.getAcTemp();
        if (curTemp == -1) {
            ToastUtils.showShort(R.string.ir_not_support_temp_tip);
            return;
        }

        //更新状态
        //temp
        TemperatureRange range = mIrDecode.getTemperatureRange(mAcStatus.getAcMode());
        if (curTemp > range.getTempMin()) {
            curTemp--;
            if (curTemp < 0) {
                curTemp = 0;
            }
        }
        mAcStatus.setAcTemp(curTemp);
        mModeTempMap.put(mAcStatus.getAcMode(), curTemp);

        //通知状态刷新
        notifyStatusChanged();

        //发送红外码
        int keyCode = IrAcKey.TEMP_MINUS.getValue();
        int[] codes = mIrDecode.decodeBinary(keyCode, mAcStatus, 0);
        mIrManager.transmit(FREQUENCY, codes);
        Log.e(TAG, "handleTempMinusKey: send ir code");

    }

    /**
     * 风力（即风速）按键处理
     */
    private void handleWindSpeedKey() {
        if (isInPowerOff()) {
            ToastUtils.showShort(R.string.ir_not_use_in_power_off);
            return;
        }

        //判断当前模式是否支持风速控制
        int curSpeed = mAcStatus.getAcWindSpeed();
        if (curSpeed == -1) {
            ToastUtils.showShort(R.string.ir_not_support_speed_tip);
            return;
        }

        //更新状态
        //wind speed
        int newSpeed = curSpeed;
        List<Constants.ACWindSpeed> speedList = getSupportedWindSpeeds(mAcStatus.getAcMode());
        int index = speedList.indexOf(Constants.ACWindSpeed.getSpeedByValue(curSpeed));
        if (index >= speedList.size() - 1) {
            newSpeed = speedList.get(0).getValue();
        } else {
            newSpeed = speedList.get(index + 1).getValue();
        }
        mAcStatus.setAcWindSpeed(newSpeed);
        mModeSpeedMap.put(mAcStatus.getAcMode(), newSpeed);

        //通知状态刷新
        notifyStatusChanged();

        //发送红外码
        int keyCode = IrAcKey.WIND_SPEED.getValue();
        int[] codes = mIrDecode.decodeBinary(keyCode, mAcStatus, 0);
        mIrManager.transmit(FREQUENCY, codes);
    }

    public void handleWindSpeedKey1() {
        if (isInPowerOff()) {
            ToastUtils.showShort(R.string.ir_not_use_in_power_off);
            return;
        }

        //判断当前模式是否支持风速控制
        int curSpeed = mAcStatus.getAcWindSpeed();
        if (curSpeed == -1) {
            ToastUtils.showShort(R.string.ir_not_support_speed_tip);
            return;
        }

        //更新状态
        //wind speed
        int newSpeed = curSpeed;
        List<Constants.ACWindSpeed> speedList = getSupportedWindSpeeds(mAcStatus.getAcMode());
        int index = speedList.indexOf(Constants.ACWindSpeed.getSpeedByValue(curSpeed));
        newSpeed = speedList.get(0).getValue();
        mAcStatus.setAcWindSpeed(newSpeed);
        mModeSpeedMap.put(mAcStatus.getAcMode(), newSpeed);

        //通知状态刷新
        notifyStatusChanged();

        //发送红外码
        int keyCode = IrAcKey.WIND_SPEED.getValue();
        int[] codes = mIrDecode.decodeBinary(keyCode, mAcStatus, 0);
        mIrManager.transmit(FREQUENCY, codes);
    }

    public void handleWindSpeedKey2() {
        if (isInPowerOff()) {
            ToastUtils.showShort(R.string.ir_not_use_in_power_off);
            return;
        }

        //判断当前模式是否支持风速控制
        int curSpeed = mAcStatus.getAcWindSpeed();
        if (curSpeed == -1) {
            ToastUtils.showShort(R.string.ir_not_support_speed_tip);
            return;
        }

        //更新状态
        //wind speed
        int newSpeed = curSpeed;
        List<Constants.ACWindSpeed> speedList = getSupportedWindSpeeds(mAcStatus.getAcMode());
        int index = speedList.indexOf(Constants.ACWindSpeed.getSpeedByValue(curSpeed));
        newSpeed = speedList.get(1).getValue();
        mAcStatus.setAcWindSpeed(newSpeed);
        mModeSpeedMap.put(mAcStatus.getAcMode(), newSpeed);

        //通知状态刷新
        notifyStatusChanged();

        //发送红外码
        int keyCode = IrAcKey.WIND_SPEED.getValue();
        int[] codes = mIrDecode.decodeBinary(keyCode, mAcStatus, 0);
        mIrManager.transmit(FREQUENCY, codes);
    }

    public void handleWindSpeedKey3() {
        if (isInPowerOff()) {
            ToastUtils.showShort(R.string.ir_not_use_in_power_off);
            return;
        }

        //判断当前模式是否支持风速控制
        int curSpeed = mAcStatus.getAcWindSpeed();
        if (curSpeed == -1) {
            ToastUtils.showShort(R.string.ir_not_support_speed_tip);
            return;
        }

        //更新状态
        //wind speed
        int newSpeed = curSpeed;
        List<Constants.ACWindSpeed> speedList = getSupportedWindSpeeds(mAcStatus.getAcMode());
        int index = speedList.indexOf(Constants.ACWindSpeed.getSpeedByValue(curSpeed));
        newSpeed = speedList.get(2).getValue();
        mAcStatus.setAcWindSpeed(newSpeed);
        mModeSpeedMap.put(mAcStatus.getAcMode(), newSpeed);

        //通知状态刷新
        notifyStatusChanged();

        //发送红外码
        int keyCode = IrAcKey.WIND_SPEED.getValue();
        int[] codes = mIrDecode.decodeBinary(keyCode, mAcStatus, 0);
        mIrManager.transmit(FREQUENCY, codes);
    }

    public void handleWindSpeedKey4() {
        if (isInPowerOff()) {
            ToastUtils.showShort(R.string.ir_not_use_in_power_off);
            return;
        }

        //判断当前模式是否支持风速控制
        int curSpeed = mAcStatus.getAcWindSpeed();
        if (curSpeed == -1) {
            ToastUtils.showShort(R.string.ir_not_support_speed_tip);
            return;
        }

        //更新状态
        //wind speed
        int newSpeed = curSpeed;
        List<Constants.ACWindSpeed> speedList = getSupportedWindSpeeds(mAcStatus.getAcMode());
        int index = speedList.indexOf(Constants.ACWindSpeed.getSpeedByValue(curSpeed));
        newSpeed = speedList.get(3).getValue();
        mAcStatus.setAcWindSpeed(newSpeed);
        mModeSpeedMap.put(mAcStatus.getAcMode(), newSpeed);

        //通知状态刷新
        notifyStatusChanged();

        //发送红外码
        int keyCode = IrAcKey.WIND_SPEED.getValue();
        int[] codes = mIrDecode.decodeBinary(keyCode, mAcStatus, 0);
        mIrManager.transmit(FREQUENCY, codes);
    }

    /**
     * 扫风按键处理
     */
    private void handleSweepWindKey() {
        if (isInPowerOff()) {
            ToastUtils.showShort(R.string.ir_not_use_in_power_off);
            return;
        }

        //判断当前模式是否支持风速控制
        int curSweepWind = mAcStatus.getAcWindDir();
        if (curSweepWind == -1) {
            ToastUtils.showShort(R.string.ir_not_support_sweep_wind_tip);
            return;
        }

        //更新状态
        //wind dir
        int newSweepWind = curSweepWind;
        if (curSweepWind == Constants.ACSwing.SWING_ON.getValue()) {
            newSweepWind = Constants.ACSwing.SWING_OFF.getValue();
        } else {
            newSweepWind = Constants.ACSwing.SWING_ON.getValue();
        }
        mAcStatus.setAcWindDir(newSweepWind);
        mModeSwingMap.put(mAcStatus.getAcMode(), newSweepWind);

        //通知状态刷新
        notifyStatusChanged();

        //发送红外码
        int keyCode = IrAcKey.SWEEP_WIND.getValue();
        int[] codes = mIrDecode.decodeBinary(keyCode, mAcStatus, 0);
        mIrManager.transmit(FREQUENCY, codes);
    }

    /**
     * 判断当前是否处于电源关闭状态
     *
     * @return true:当前处于电源关闭状态
     */
    private boolean isInPowerOff() {
        return mAcStatus.getAcPower() == Constants.ACPower.POWER_OFF.getValue();
    }

    /**
     * 获取某一模式下所支持的风档（即风速）列表
     *
     * @param mode 空调模式
     * @return
     */
    private List<Constants.ACWindSpeed> getSupportedWindSpeeds(int mode) {
        int[] windSpeeds = mIrDecode.getACSupportedWindSpeed(mode);
        List<Constants.ACWindSpeed> windSpeedList = new ArrayList<>();
        for (int i = 0; i < windSpeeds.length; i++) {
            if (windSpeeds[i] == 1) {
                windSpeedList.add(Constants.ACWindSpeed.getSpeedByValue(i));
            }
        }
        return windSpeedList;
    }

    @Override
    public void saveRemote(@NonNull String name) {
        if (mRemoteIndex == null || TextUtils.isEmpty(name)) {
            return;
        }

        mRemote = IrUtil.convertRemoteIdx2Remote(mRemoteIndex);
        mRemote.name = name;
        AcRemoteStatusInfo statusInfo = createRemoteStatusInfo();
        mRemote.statusInfo = GsonUtils.toJson(statusInfo);
        int id = IrRemoteDbHelper.insert(mRemote);
        mRemote.id = id;
    }

    @Override
    public void updateRemote(@NonNull String name) {
        if (mRemote == null || TextUtils.isEmpty(name)) {
            return;
        }
        mRemote.name = name;
        updateStatus2Db();
    }

    private void updateStatus2Db() {
        if (mRemote == null) return;
        AcRemoteStatusInfo statusInfo = createRemoteStatusInfo();
        mRemote.statusInfo = GsonUtils.toJson(statusInfo);
        IrRemoteDbHelper.update(mRemote);
    }

    private AcRemoteStatusInfo createRemoteStatusInfo() {
        AcRemoteStatusInfo statusInfo = new AcRemoteStatusInfo();
        statusInfo.acStatus = mAcStatus;
        statusInfo.setStrModeTempMap(mModeTempMap);
        statusInfo.setStrModeSpeedMap(mModeSpeedMap);
        statusInfo.setStrModeSwingMap(mModeSwingMap);
        return statusInfo;
    }

    private void notifyStatusChanged() {
        if (listener != null && mAcStatus != null) {
            listener.onAcStatusChanged(mAcStatus);
        }
        updateStatus2Db();
    }

    private IListener listener;

    public void setListener(IListener listener) {
        this.listener = listener;
        notifyStatusChanged();
    }

    public interface IListener {

        void onAcStatusChanged(@NonNull ACStatus status);

    }

}
